import React, {useRef} from 'react';
import { Global } from "@emotion/react";
import RoutingContext from './RoutingContext';
import { ErrorBoundary } from "react-error-boundary";
import HashLinkObserver from "react-hash-link";
import {首页设备概况nbh} from "../report/vessel/repView";
// import {UrlPrint} from "../comp/Print";
import {DeviceSurvey} from "../9sppt";

//JS毛病：useTransition,没有定义的也不会告警，运行报错才知道的。
const { useContext, useEffect,  Suspense, useState } = React;

//const SUSPENSE_CONFIG = { timeoutMs: 2000 };

function  errTranslate(error){
  let dispaly;
  if(error.message === 'Failed to fetch')
    dispaly="后端没响应啊";
  else dispaly=error.message;
  return dispaly;
}

/**整个应用APP的最高层起点，工程起点/index.tsx使用它作为函数组件；这个算Hook可用的React范围下的组件函数。
 * A component that accesses the current route entry from RoutingContext and renders
 * that entry.
 */
export default function RouterRenderer() {
  // Access the router
  const router = useContext(RoutingContext);
  // Improve the route transition UX by delaying transitions: show the previous route entry
  // for a brief period while the next route is being prepared. See
  // https://reactjs.org/docs/concurrent-mode-patterns.html#transitions
//  const [startTransition, isPending] = useTransition(SUSPENSE_CONFIG);

  // Store the active entry in state - this allows the renderer to use features like
  // useTransition to delay when state changes become visible to the user.
  //? router.get()是旧的页面路由的？
  const [routeEntry, setRouteEntry] = useState(router.get());

  // On mount subscribe for route changes
  useEffect(() => {
    // Check if the route has changed between the last render and commit:
    const currentEntry = router.get();
    if (currentEntry !== routeEntry) {
      // if there was a concurrent modification, rerender and exit
      setRouteEntry(currentEntry);
      return;
    }
    //切换路由还有的搞
    // If there *wasn't* a concurrent change to the route, then the UI
    // is current: subscribe for subsequent route updates
    //真正？入口点 router.subscribe( 里面cb函数部分 )subscribers.set(id, cb)登记回调了;
    //这里只会执行一次；
    const dispose = router.subscribe(nextEntry => {
      // startTransition() delays the effect of the setRouteEntry (setState) call
      // for a brief period, continuing to show the old state while the new
      // state (route) is prepared.
      /*startTransition(() => { 试验版本的，react实验版也无法集成进来！
        setRouteEntry(nextEntry); ？？可不需要提供延迟时间片大小
      });
      无法确保回调函数不会在组件卸载后调用，一旦出现报错。任何异步事件都应该在组件卸载时取消订阅；
      幸亏，let timer = setTimeout(()=>回调这里的动作涉及的 <RouterRenderer />也只会加载一次。
      【允许】history.push()或Link点击后，组件更新页面的延迟执行，但是数据加载却不受此延迟阻碍。
      */
      setRouteEntry(nextEntry);
    });
    return () => dispose();

    // Note: this hook updates routeEntry manually; we exclude that variable
    // from the hook deps to avoid recomputing the effect after each change
    // triggered by the effect itself.
    // eslint-disable-next-line
  }, [router]);

  // The current route value is an array of matching entries - one entry per
  // level of routes (to allow nested routes). We have to map each one to a
  // RouteComponent to allow suspending, and also pass its children correctly.
  // Conceptually, we want this structure:
  // 多层次的嵌套 路由表！
  // ```
  // <RouteComponent
  //   component={entry[0].component}
  //   prepared={entrry[0].prepared}>
  //   <RouteComponent
  //     component={entry[1].component}
  //     prepared={entry[1].prepared}>
  //       // continue for nested items...
  //   </RouteComponent>
  // </RouteComponent>
  // ```
  // To achieve this, we reverse the list so we can start at the bottom-most
  // component, and iteratively construct parent components w the previous
  // value as the child of the next one:
  const reversedItems = [].concat(routeEntry.entries).reverse(); // reverse is in place, but we want a copy so concat
    //console.log("顶级多个？reversedItems=", reversedItems);
    const firstItem = reversedItems[0];         //顺序正好相反了，儿子在最前面。

  //顶级多个？
  if(!firstItem){
    return null;
  }
    //【缺点】这里儿子辈routeData没有传递给父辈组件，上级路由组件不知道下一级路由组件的路由数据啊。子路由反而更早发送数据请求。
  // the bottom-most component is special since it will have no children
  // (though we could probably just pass null children to it)
    let routeComponent = (
        <RouteComponent
            component={firstItem.component}
            prepared={firstItem.prepared}
            routeData={firstItem.routeData}
        />
    );
    //多层次 嵌套的 路由。 中间加 <Suspense 可避免上级组件也要闪一闪的。
    //添加<Suspense fallback={'加载中 ...'}></Suspense>导致报告模板加载问题,【顺序相反了】儿子反而提前准备数据，报告模板组件也是放在prepare才动态加载的。
    //【约束】加了<Suspense之后就无法跨越上下级路由组件去传递参数:无法在上下级两个路由Main组件之间用普通方式传递数据的:props{??}模式。
    //上下级路由两页面，Relay变更后返回report的data数据,左边页面就能立刻显示更新的。若套用EditStorageContext.Provider更快setState()修改也能同步给另外页面，Relay要保存才行！Context上下级嵌套组件才行。
    for (let ii = 1; ii < reversedItems.length; ii++) {
        const nextItem = reversedItems[ii];
        //顶级多个？
        if(!nextItem)
          break;
        routeComponent = (
            <RouteComponent
              component={nextItem.component}
              prepared={nextItem.prepared}
              routeData={nextItem.routeData}
            >
                <Suspense fallback={'加载中 ...'}>
                {routeComponent}
                </Suspense>
            </RouteComponent>
        );
    }

 // console.log("当前render路由页？reversedItems=",reversedItems.length,":", reversedItems);
  // Routes can error so wrap in an <ErrorBoundary>
  // Routes can suspend, so wrap in <Suspense>
  /**这底下routeComponent已经是嵌套路由后的结果,【注意】hash#滚动在浏览器开启调试窗口占用可视窗口宽度情形可能少了一点，定位偏小了。
   *【缺点】无法在路由器配置的从上级往下级路由组件传递Props ...props的参数。静态路由器？ 动态路由嵌入各个页面组件的路由?能自由传递props？
   * margin对付BUG的：Chrome版本116.0.5845.118 最后有3个预防表格右边线被截切的就正常了。而117.0.5938.92版本Chrome就有问题了不勾选页眉页脚的就被截切。
   * 页面哈希路由方式的直接支持：<HashLinkObserver /> 支持动态载入的数据或模板页面组件。
   * */
  return (
      <React.Fragment>

              <Global
                  styles={{
                      body: {
                          margin: 0,
                          padding: 0,
                          "@media print": {
                              margin: '0 1px 0 0',     //对付BUG的
                          },
                      },
                      html: {
                          //       width: "190mm",
                      },

                  }}
                  /*  css={ [ { padding: "0px" } ,
                      css`@page {
                        size: A4;
                      }`,
                    ] } */
              />
              <ErrorBoundary fallbackRender={({ error }) => <div>
                  报错就得刷新 等活儿再试： {errTranslate(error)}
                  <h3>打电话找维护人员</h3> <h4><a href={"/"}>返回首页</a></h4>
              </div>}
              >
                  <Suspense fallback={'Loading fallback...'}>
                      <HashLinkObserver />
                      {/* Indicate to the user that a transition is pending, even while showing the previous UI
                  删除掉了startTransition; 效果不好。
                */}
                      {routeComponent}
                  </Suspense>
              </ErrorBoundary>

      </React.Fragment>
  );
}

/**
 * The `component` property from the route entry is a Resource, which may or may not be ready.
 * We use a helper child component to unwrap the resource with component.read(), and then
 * render it if its ready.
 *
 * NOTE: calling routeEntry.route.component.read() directly in RouteRenderer woldn't work the
 * way we'd expect. Because that method could throw - either suspending or on error - the error
 * would bubble up to the *caller* of RouteRenderer. We want the suspend/error to bubble up to
 * our ErrorBoundary/Suspense components, so we have to ensure that the suspend/error happens
 * in a child component.
 * 这底下 prepared 是graphql 预先获取的查询结果数据。
 * 真正路由 实际上用 RoutingContext 注入的。
 */
function RouteComponent(props) {
    // console.log("RouteComponent基递两级组件props=",props);
  //静态路由【】里面配置的props.component实际上只是相应组件的源代码，并不是React组件本尊，不能直接用来render()的。
  //假如路由表设置的props.component是通常意义的React.Component的情况，那么就没必要下面添加component.read();我这里都是源代码资源指代的。
  if(!props.component) {
        //  route.component.load(); //触发加载源代码
    return null;    //还未加载完成吧
  }

 // var _resource$read = props.component.read();
  //只能是单一个文件名的缺省输出的！
 // const  Component = _resource$read["default"];
    const Component = props.component;

  //必须提前触发加载，否则上面这里props.component可能为空的。
  const { routeData, prepared } = props;
  //console.log("RouteCompon反递归props=", props,"matchData=",routeData);

  return (
    <Component
      routeData={routeData}
      prepared={prepared}
      children={props.children}
    />
  );
}


/*
本路由器观察到：分层级的路由配置下，在同一个上一级路由底下的多个子路由对应path切换URL的，对应组件保持不会unmount,若该组件对应path部分切换了就会重新加载mount。
    const mountedRef = useRef(false);
    if(!mountedRef.current) {
        mountedRef.current = true;
        console.log("加载初始化DeviceMain期间:",props,"filter=",props.prepared.filter);
    }
新的V6版本React Router可行？ 就缺了prepareData()?
    element = useRoutes([
        {
          path: "invoices",
          element: <Invoices />,
          children: [
            { path: ":id", element: <Invoice /> },
          ],
        },
      ]);
标准看   https://developer.mozilla.org/en-US/docs/Web/CSS/@page
打印控制css：有的不起作用啊 https://blog.csdn.net/u013994400/article/details/127898477
    css={ [ {
            "@media print": {
                pageBreakBefore: 'always',
            },
        "@page": {
                size: 'A4 landscape',
            },
         "@page :first": {
             size: 'A4 portrait',
            },
        } ,css`@page:right{
                      @bottom-right {
                        content: counter(page);
                      }
                    }
                      @page:left{
                        @bottom-left {
                          content: "Page " counter(page) " of " counter(pages);
                        }
                      }
                    `,
    ] }
    css` @page chapter {
              size: a4 landscape;
            }
          @page {
                page: chapter;
              }`,
        ] }
* */

